#pragma once

#include <opencv2\opencv.hpp>

#include "fiocpp.hpp"
#include "fiowin.hpp"
#include <thread>


class ConcatPage
{
public:
	static bool ConcatImage(std::string fop, int i, const char *formatIn, const char *formatOut, bool rotateLeft = false, bool rotateRight = false, int compress=3)
	{
		char buf[64];
		sprintf(buf, formatIn, i);
		cv::Mat right = cv::imread(fop + std::string(buf), CV_LOAD_IMAGE_UNCHANGED);
		if (right.empty())
		{
			std::cout << "fail load image: " << fop + std::string(buf) << "\n";
			return false;
		}
		if (rotateRight) cv::flip(right, right, -1);

		sprintf(buf, formatIn, i + 1);
		cv::Mat left = cv::imread(fop + std::string(buf), CV_LOAD_IMAGE_UNCHANGED);
		if (left.empty())
		{
			std::cout << "fail load image: " << fop + std::string(buf) << "\n";
			return false;
		}
		if (rotateLeft) cv::flip(left, left, -1);

		if (left.channels() != right.channels() || left.rows != right.rows)
		{
			std::cout << "two image not match\n";
			return false;
		}

		sprintf(buf, formatOut, i, i + 1);

		std::vector<int> compression_params;
		compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
		compression_params.push_back(compress);

		cv::Mat mp;
		cv::hconcat(left, right, mp);
		bool res = cv::imwrite(fop + std::string(buf), mp, compression_params);

		if (!res)
		{
			std::cout << "fail save image: " << fop + std::string(buf) << "\n";
			return false;
		}

		return true;

	}

	static void Concat(std::string fop, size_t nThread = 4, bool rotateLeft = false, bool rotateRight = false, int minPage = 8, int maxPage = 200, int compress = 3)
	{
		std::vector<std::thread> ths;

		for (int i = minPage; i < maxPage; i += 2)
		{
			std::cout << i << '\n';

			ths.push_back(std::thread(ConcatImage, fop, i, "IMG_%04d_Cut.png", "IMG_%03d_%03d.png", rotateLeft, rotateRight, compress));

			if (ths.size() >= nThread)
			{
				ths[0].join();
				ths.erase(ths.begin());
			}
		}

		for (auto &th : ths)
			th.join();
	}

	bool rotateLeft;
	bool rotateRight;
	int minPage;
	int maxPage;
	int compress;
	int nThread;

	ConcatPage()
		: rotateLeft(false)
		, rotateRight(false)
		, minPage(8)
		, maxPage(200)
		, compress(3)
		, nThread(1)
	{

	}

	void Load(const CvFileStorage* fs)
	{
		rotateLeft = cvReadIntByName(fs, 0, "rotateLeft", rotateLeft);

		rotateRight = cvReadIntByName(fs, 0, "rotateRight", rotateRight);

		minPage = cvReadIntByName(fs, 0, "minPage", minPage);

		maxPage = cvReadIntByName(fs, 0, "maxPage", maxPage);

		compress = cvReadIntByName(fs, 0, "compress", compress);

		nThread = cvReadIntByName(fs, 0, "nThread", nThread);
	}

	bool Load(std::string configFile)
	{
		CvFileStorage* fs = cvOpenFileStorage(configFile.c_str(), 0, CV_STORAGE_READ);
		if (fs)
		{
			Load(fs);
			cvReleaseFileStorage(&fs);
			return true;
		}
		std::cout << "fail load " << configFile << "\n";
		return false;
	}


	void Save(CvFileStorage* fs)
	{
		cvWriteInt(fs, "rotateLeft", rotateLeft);

		cvWriteInt(fs, "rotateRight", rotateRight);

		cvWriteInt(fs, "minPage", minPage);

		cvWriteInt(fs, "maxPage", maxPage);

		cvWriteInt(fs, "compress", compress);

		cvWriteInt(fs, "nThread", nThread);
	}

	bool Save(std::string configFile)
	{
		CvFileStorage* fs = cvOpenFileStorage(configFile.c_str(), 0, CV_STORAGE_WRITE);
		if (fs)
		{
			Save(fs);
			cvReleaseFileStorage(&fs);
			return true;
		}
		std::cout << "fail save " << configFile << "\n";
		return false;
	}


	void RunCat(std::string path, std::string paramPath)
	{
		Load(paramPath);
		Concat(path, nThread, rotateLeft, rotateRight, minPage, maxPage, compress);
	}
};

